import { Request, Response, NextFunction } from 'express';
import { Prisma } from '@prisma/client';

// 自定义错误类
export class CustomError extends Error {
  public statusCode: number;
  public isOperational: boolean;

  constructor(message: string, statusCode: number) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;

    Error.captureStackTrace(this, this.constructor);
  }
}

// 认证错误类
export class AuthenticationError extends CustomError {
  constructor(message: string = '认证失败') {
    super(message, 401);
  }
}

// 授权错误类
export class AuthorizationError extends CustomError {
  constructor(message: string = '权限不足') {
    super(message, 403);
  }
}

// 冲突错误类
export class ConflictError extends CustomError {
  constructor(message: string = '数据冲突') {
    super(message, 409);
  }
}

// 未找到错误类
export class NotFoundError extends CustomError {
  constructor(message: string = '资源未找到') {
    super(message, 404);
  }
}

// 验证错误类
export class ValidationError extends CustomError {
  constructor(message: string = '数据验证失败') {
    super(message, 400);
  }
}

// 自定义错误类
export class AppError extends Error {
  public statusCode: number;
  public isOperational: boolean;

  constructor(message: string, statusCode: number) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;

    Error.captureStackTrace(this, this.constructor);
  }
}

// 错误处理中间件
export const errorHandler = (
  error: Error | AppError,
  req: Request,
  res: Response,
  next: NextFunction
) => {
  let statusCode = 500;
  let message = '服务器内部错误';
  let details: any = null;

  // 处理自定义应用错误
  if (error instanceof AppError) {
    statusCode = error.statusCode;
    message = error.message;
  }
  // 处理Prisma错误
  else if (error instanceof Prisma.PrismaClientKnownRequestError) {
    switch (error.code) {
      case 'P2002':
        statusCode = 409;
        message = '数据已存在';
        details = { field: error.meta?.target };
        break;
      case 'P2025':
        statusCode = 404;
        message = '记录不存在';
        break;
      case 'P2003':
        statusCode = 400;
        message = '外键约束失败';
        details = { field: error.meta?.field_name };
        break;
      case 'P2014':
        statusCode = 400;
        message = '关系约束失败';
        break;
      default:
        statusCode = 400;
        message = '数据库操作失败';
        details = { code: error.code };
    }
  }
  // 处理Prisma验证错误
  else if (error instanceof Prisma.PrismaClientValidationError) {
    statusCode = 400;
    message = '数据验证失败';
    details = { error: error.message };
  }
  // 处理JWT错误
  else if (error.name === 'JsonWebTokenError') {
    statusCode = 401;
    message = '无效的令牌';
  }
  else if (error.name === 'TokenExpiredError') {
    statusCode = 401;
    message = '令牌已过期';
  }
  // 处理Multer错误
  else if (error.name === 'MulterError') {
    switch (error.code) {
      case 'LIMIT_FILE_SIZE':
        statusCode = 413;
        message = '文件大小超出限制';
        break;
      case 'LIMIT_FILE_COUNT':
        statusCode = 413;
        message = '文件数量超出限制';
        break;
      case 'LIMIT_UNEXPECTED_FILE':
        statusCode = 400;
        message = '意外的文件字段';
        break;
      default:
        statusCode = 400;
        message = '文件上传失败';
    }
  }
  // 处理验证错误
  else if (error.name === 'ValidationError') {
    statusCode = 400;
    message = '数据验证失败';
    details = { error: error.message };
  }
  // 处理语法错误
  else if (error instanceof SyntaxError) {
    statusCode = 400;
    message = '请求格式错误';
    details = { error: error.message };
  }
  // 处理其他已知错误
  else if (error.message) {
    // 检查是否是已知的错误消息
    if (error.message.includes('ECONNREFUSED')) {
      statusCode = 503;
      message = '数据库连接失败';
    } else if (error.message.includes('ENOTFOUND')) {
      statusCode = 503;
      message = '服务不可用';
    } else if (error.message.includes('ETIMEDOUT')) {
      statusCode = 504;
      message = '请求超时';
    } else {
      // 保留原始错误消息，但限制长度
      message = error.message.length > 100 
        ? error.message.substring(0, 100) + '...' 
        : error.message;
    }
  }

  // 记录错误日志
  console.error('错误详情:', {
    timestamp: new Date().toISOString(),
    method: req.method,
    url: req.url,
    statusCode,
    message: error.message,
    stack: error.stack,
    userAgent: req.get('User-Agent'),
    ip: req.ip,
    userId: (req as any).user?.id
  });

  // 开发环境返回详细错误信息
  if (process.env.NODE_ENV === 'development') {
    details = {
      ...details,
      stack: error.stack,
      name: error.name,
      message: error.message
    };
  }

  // 发送错误响应
  res.status(statusCode).json({
    success: false,
    error: message,
    ...(details && { details }),
    ...(process.env.NODE_ENV === 'development' && { 
      timestamp: new Date().toISOString(),
      path: req.url,
      method: req.method
    })
  });
};

// 异步错误包装器
export const asyncHandler = (fn: Function) => {
  return (req: Request, res: Response, next: NextFunction) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
};

// 404错误处理
export const notFoundHandler = (req: Request, res: Response) => {
  res.status(404).json({
    success: false,
    error: '接口不存在',
    path: req.url,
    method: req.method
  });
};

// 请求超时处理
export const timeoutHandler = (timeout: number) => {
  return (req: Request, res: Response, next: NextFunction) => {
    const timer = setTimeout(() => {
      if (!res.headersSent) {
        res.status(408).json({
          success: false,
          error: '请求超时',
          timeout: timeout
        });
      }
    }, timeout);

    res.on('finish', () => {
      clearTimeout(timer);
    });

    next();
  };
};

// 全局错误处理
export const globalErrorHandler = (
  error: Error,
  req: Request,
  res: Response,
  next: NextFunction
) => {
  // 如果响应已经发送，委托给默认错误处理器
  if (res.headersSent) {
    return next(error);
  }

  // 使用自定义错误处理器
  errorHandler(error, req, res, next);
};

// 未捕获的异常处理
process.on('uncaughtException', (error: Error) => {
  console.error('未捕获的异常:', error);
  process.exit(1);
});

// 未处理的Promise拒绝处理
process.on('unhandledRejection', (reason: any, promise: Promise<any>) => {
  console.error('未处理的Promise拒绝:', reason);
  console.error('Promise:', promise);
  process.exit(1);
});
